Sissejuhatus
Siin praktikumis jätkame ggplot2 võimaluste õppimisega. Selleks, et
tööga pihta saaks hakata, loeme sisse vajalikud paketid ja
andmestiku.
library(ggplot2)
library(tidyverse)
load("linnad.RData", verbose = T)
Loading objects:
linnad
Faktoritega töötamine
Pakett ggplot2 üritab võimalikult palju kasutada joonistamisel
informatsiooni mis on kodeeritud faktori tasemetesse. Faktor on
andmetüüp diskreetsetele muutujatele, mis säilitab lisaks väärtustele ka
info küigi võimalike väärtuste ning nende järjestuste kohta. Faktori
taseme nimede põhjal joonistatakse näiteks legend ja taseme järjestust
kasutatakse telgedel elementide järjestamiseks. Seetõttu on oluline
tunda paari nippi kuidas faktorite tasemetega töötada.
Esiteks on kasulik panna faktori tasemetele sisukad nimed. Seda saab
teha andes käsule factor ette juba sisukate nimedega
sõnevektori, kasutades argumenti labels.
a = factor(c(1, 1, 1, 2, 2, 3), labels = c("A", "B", "C"))
a
[1] A A A B B C
Levels: A B C
Faktori tasemete nimesid saab muuta kasutades käsku
fct_recode (tuleb kaasa tidyverse paketiga).
Sellega saab ka faktori tasemeid kokku võtta.
fct_recode(a, "I" = "A", "II" = "B", "III" = "C")
[1] I I I II II III
Levels: I II III
fct_recode(a, "I" = "A", "II" = "B")
[1] I I I II II C
Levels: I II C
fct_recode(a, "I" = "A", "II" = "B", "I" = "C")
[1] I I I II II I
Levels: I II
Faktori tasemete järjestust saab muuta ka käsuga
fct_relevel, kus etteantud tasemed tõstetakse jäjekorras
ette poole
a = factor(c(1, 1, 1, 2, 2, 3), labels = c("A", "B", "C"))
a
[1] A A A B B C
Levels: A B C
fct_relevel(a, "C")
[1] A A A B B C
Levels: C A B
fct_relevel(a, "C", "B", "A")
[1] A A A B B C
Levels: C B A
Kui me tahame muuta faktorite järjekorda mingi teise vektori järgi,
siis saab kasutada käsku fct_reorder.
a = factor(c(1, 1, 1, 2, 2, 3), labels = c("A", "B", "C"))
b = c(1, 5, 6, 2, -4, 10)
a
[1] A A A B B C
Levels: A B C
b
[1] 1 5 6 2 -4 10
fct_reorder(a, b)
[1] A A A B B C
Levels: B A C
fct_reorder(a, b, .desc = T)
[1] A A A B B C
Levels: C A B
fct_reorder(a, b, .fun = max)
[1] A A A B B C
Levels: B A C
Seega kui me tahame mugandada pilti on tihtipeale kasulikum enne
mugandada andmeid ja siis nendega pilt joonistada.
ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = income_class)) +
geom_point()

linnad %>%
mutate(income_class = fct_recode(income_class, "High" = "Very High", "Low" = "Very Low", "Low" = "Medium")) %>%
ggplot(aes(x = per_capita_inc, y = unemployment_rate, colour = income_class)) +
geom_point()

ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = Poverty_factor)) +
geom_point()

linnad %>%
mutate(Poverty_factor = fct_relevel(Poverty_factor, "Low", "Medium", "High")) %>%
ggplot(aes(x = per_capita_inc, y = unemployment_rate, colour = Poverty_factor)) +
geom_point()

ggplot(linnad, aes(x = County, y = pop_estimate)) +
geom_bar(stat = "identity")

linnad %>%
mutate(County = fct_reorder(County, pop_estimate)) %>%
ggplot(aes(x = County, y = pop_estimate)) +
geom_bar(stat = "identity")

Ülesanded
- Joonistage seos bachelor ja high_scl vahel ning
näidake värviga tunnust income_class . Võta koku klassid “Very
Low” ja “Low” ning uuda värvide järjekord nii, et see algaks väga
kõrgest ja lõppeks madalaga.
linnad %>%
mutate(income_class = fct_recode(income_class, "Low" = "Very Low")) %>%
mutate(income_class = fct_relevel(income_class, "Low", "Medium", "High", "Very High" )) %>%
ggplot(aes(x = bachelor , y = high_scl , colour = income_class )) +
geom_point()

Graafikute annoteerimine ja mugandamine
Graafikute annoteerimine
Telgede ja graafiku annoteerimise viise me oleme juba töö käigus
näinud. Paljud asjad saab ära lahendada erinevate
skaleerimisfunktsioonide parameetritega. Siiski on paljudele neis olemas
ka mugavamad vasted eraldi funktsioonidega mis hoiavad trükkimist kokku.
Neist olulisemad on
ggtitle() - määrame graafiku pealkirja
xlab(), ylab() - telgede
pealkirjad
xlim(), ylim() - telgede
väärtusvahemiku määramine
Graafikute stiil
Vahest on vaja muuta ggplot2 graafikute üleüldist stiili
või mõne elemendi väljanägemist. Näiteks on standardne
ggplot2 graafikute taust hall, mis ei ole alati parim
lahendus. Seda on lihtne muuta käsuga theme_bw mis teeb
tausta valgeks ja muudab ka portsu muude graafiku elementide värve ja
kuju.
ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = birth_class)) +
geom_point() +
theme_bw()

Neid funktsioone on veel, tasub vaadata mida RStudio pakub, kui
kirjutada algus theme_ . Veel rohkem erinevaid teemasid on
olemas paketis ggthemes (https://yutannihilation.github.io/allYourFigureAreBelongToUs/ggthemes/).
library(ggthemes)
ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = birth_class)) +
geom_point() +
theme_wsj()

Täpsemalt saab muuta konkreetseid elemente käsuga theme.
Siin on terve ports parameetreid mis töötavad hierarhiliselt. Olulisemad
on toodud järgmisel joonisel.
Nendele saabväärtuseks anda käske element_text,
element_line ja element_rect vastavalt
parameetri tüübile. Käskude element_* parameetrid vastavad
suhteliselt täpselt sarnaste elementide grid paketis kasutatavatele
parameetritele. Oluline funktsioon on ka element_blank mis vastava
elemendi lihtsalt ära kustutab.
ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = birth_class)) +
geom_point() +
theme(panel.background = element_rect(fill = "pink"), panel.grid.minor = element_blank())

Väga oluline parameeter käsus theme on ka
legend.position. Kui selle väärtuseks on
"none" kustutatakse legend ära. Väärtused
"left", "right", "top" ja
"bottom" käituvad nagu võiks oodata . Andes ette kahe
elemendilise vektori paigutab ta legendi graafiku ala sees vastavalt
antud koordinaatidele, paralleelselt on hea kasutada ka
legend.justification argumenti, mis võimaldab legendi
paigutust täpsemalt kontollida.
ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = birth_class)) +
geom_point() +
theme(legend.position = "none")
ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = birth_class)) +
geom_point() +
theme(legend.position = "bottom")
ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = birth_class)) +
geom_point() +
theme(legend.position = c(1,1), legend.justification = c(1, 1))
Ülesanded
- Proovi saavutada umbes järgmine pilt.

ggplot(linnad, aes(x = bachelor, y = high_scl, colour = income_class)) +
geom_point() +
scale_color_brewer(type="div", palette=2) +
ggtitle("High School and Higher Education") +
theme(
panel.background = element_rect(fill = "gold"),
axis.text.x = element_text(angle=45),
legend.position = c(1,0),
legend.justification = c(1, 0),
legend.background = element_rect(color = "black"),
legend.key = element_rect(fill = "grey95")
)
Graafikute salvestamine
Grafikuid saab salvestada käsuga ggsave(), Kui ette anda
vaid faili nimi, siis salvestab see käsk viimase graafiku, mis sai
joonistatud, kusjuures suuruse võtab ta akna järgi ning failitüübi
määrab faili nime laiendi järgi.
Parameetreid width ja height kasutades on
võimalik ära määrata ka täpselt joonise mõõdud (tollides).
ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = Poverty_factor)) +
geom_point() +
theme(legend.position = c(1,1), legend.justification = c(1, 1))
ggsave("plot1.png")
ggsave("plot1.pdf")
ggsave("plot1_wide.png", width = 10, height = 5)
Soovitav on salvestada jooniseid .pdf formaadis. Nii tehakse
vektorgraafika ja pilt on alati hea kvaliteediga. Kui soovida
(Windowsil), et kas raster kujul salvestatud pildid näiteks .png failid
head välja näeksid tasub muuta vaikimisi graafika mootorit RStudios
järgnevalt.

Erinevate graafikute kokku panemine
Graafikute tahkudeks jagamine toimib väga hästi, kui me tahame ühte
tüüpi graafikut jagada mitmeks. Kuid kui me tahame erinevat tüüpi
graafikuid erinevatel muutujatel samal pildil kõrvuti näidata, siis sama
lähenemine ei tööta. Siin tulevad appi lisapaketid. Näiteks
patchwork on üks mis võimaldab ggplot2
graafikuid kokku panna.
Enne, kui läheme patchwork-i enda juurde vaatame ühte
kasulikku nippi. Nimelt on võimalik ggplot graafik muutujana salvetada.
Joonistatakse see alles siis kui muutuja väärtus on vaja välja
trükkida.
p = ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = Poverty_factor)) +
geom_point()
p
p + theme_bw()
Loeme sisse paketi patchwork ja defineerime kolm graafikut mida
kombineerima hakata.
install.packages("patchwork")
library(patchwork)
p1 = ggplot(linnad, aes(x = per_capita_inc)) +
geom_histogram() +
ggtitle("Plot 1")
p2 = ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = Poverty_factor)) +
geom_point() +
ggtitle("Plot 2")
p3 = ggplot(linnad, aes(x = State, y = unemployment_rate, fill = State)) +
geom_boxplot() +
ggtitle("Plot 3")
p1
p2
p3
Patchworkis tehakse ka graafikutega “tehteid”. Selleks, et graafikuid
kõrvuti panna on tehe |.
p1 | p2
Üksteise alla saab panna graafikuid tehtega / .
p1/p2

Tehteid saab ka kombineerida, siis tuleb tähelepanu juhtida tehete
järjekorrale
p1 | p2 / p3

(p1 | p2) / p3

Selleks, et piltide paigutust paremini kontrollida on funktsioon
plot_layout, millega saab joonise erinevaid aspekte muuta.
Näiteks heights parameeter võimaldab muuta piltide
suhtelisi kõrguseid.
p1 / p2 / p3 + plot_layout(heights = c(2, 2, 4))
install.packages("patchwork")
Warning in install.packages :
package ‘patchwork’ is in use and will not be installed

Argument widths töötab sama moodi.
(p1 | p2 | p3) + plot_layout(widths = c(2, 2, 4))

Eelmine pilt jäi kole sest vastavate laiustega on graafikute andmeid
näitavad paneelid. Kuna kahel graafikul on aga legend, siis nende laiust
arvesse ei võeta. Küll aga on võimalik argumendiga guides kõikidelt
piltidelt legendid kokku koguda.
(p1 | p2 | p3) + plot_layout(widths = c(2, 2, 4), guides = "collect")

Paketis patchwork on veel palju võimalusi ja tasub uurida paketi
kodulehte https://github.com/thomasp85/patchwork ja seal viidatud
õpetusi.
Ülesanded
- Proovige tekitada järgnev pilt

(p1 / ( p2 | p3)) + plot_layout(widths = c(2, 2, 4), guides = "collect")

Kodune ülesanne
Proovi joonistada võimalikult sarnane graafik järgnevaga. Siin on
rakendatud terve hulk nippe, mida sai selles ja eelmises praksis õpitud.
Punktid kujunevad selle põhjal kui palju neist nippidest on rakendatud.
Kui õiget nippi on rakendatud, kuid tulemus pole täpselt identne, siis
punkte maha ei võta. Näiteks kui värv pole täpselt õige aga õigel
graafiku osal on seda siiski muudetud.

linnad
library(ggplot2)
library(dplyr)
library(patchwork)
fill_cols <- c(
"Low" = "#f4a142",
"Medium" = "gray90",
"High" = "#7b67c8"
)
outline_cols <- c(
"Low" = "#e65000",
"Medium" = "#e65000",
"High" = "#e65000"
)
data <- linnad %>%
mutate(
income_class = fct_recode(income_class, "High" = "Very High", "Low" = "Very Low"),
Poverty_factor = fct_relevel(Poverty_factor, "Low", "Medium", "High"),
Birth_factor = fct_relevel(Birth_factor, "Low", "Medium", "High")
)
p1 <- ggplot(data, aes(x = Birth_factor, y = over65, fill = Birth_factor)) +
geom_boxplot(fill = NA, color="gray5") +
geom_violin(
aes(color = Birth_factor),
alpha = 0.4, linewidth = 0,
draw_quantiles = NULL
) +
scale_fill_manual(values = fill_cols) +
scale_color_manual(values = outline_cols) +
geom_hline(yintercept = 12.5, linetype = "dotted") +
facet_wrap(~ State, ncol = 3) +
theme_bw(base_size = 13) +
theme(
strip.background = element_rect(fill = "#f2b0c4", color = "black"),
strip.text = element_text(face = "bold"),
panel.grid.major.x = element_blank(),
panel.grid.major.y = element_blank(),
panel.grid.minor = element_blank(),
panel.background = element_rect(fill = "white", color = NA),
legend.position = c(1, -0.1),
legend.justification = c(1, 0),
legend.key = element_rect( color="red"),
)
p2 <- ggplot(linnad, aes(x = deaths, y = births)) +
geom_point(color = "white", size = 2,) +
geom_smooth(color = "red", linewidth = 1) +
theme_void() +
theme(
panel.background = element_rect(fill = "black", color = "black"),
panel.grid.major = element_line(color = "white", linetype = "dashed"),
panel.grid.minor = element_line(color = "white", linetype = "dashed"),
axis.text = element_text(color = "black"),
axis.title = element_text(color = "black"),
plot.background = element_rect(fill = "white", color = "white"),
axis.title.y = element_text(angle = 90)
) +
scale_x_continuous(name = "Higher education percentage", breaks = c(0, 0.5, 1, 1.5, 2))+
labs(x = "deaths", y = "births")
p1 / p2 + plot_layout(heights = c(3, 1))

ggplot2-ga graafikute joonistamise harjutamine
Selle ja eelmise praktikumi põhjal peaks olulisemad oskused ggplot2
kasutamiseks olemas olema. Nüüd proovime neid rakendada, kasutades ka
teadmisi teisest loengust, kus sai tutvustatud graafikute valimise
põhimõtteid täpsemalt.
Loeme sisse kõigepealt andmestiku, mis kirjeldab siis 2000 inimese
kehamassi indekseid ja juhuslikul päeval tehtud sammude arvu. Iga
inimese kohta on ka antud sugu, vanus ja vanusegrupp. Loeme andmestiku
sisse.
load("bmi.RData", verbose = T)
bmi
Iga ülesande puhul tasub proovida erinevaid variante ja mõelda
milline töötab antud olukorras paremini ja miks. Meeldetuletuseks, siin
on olulisemad käsud mida vaja võib minna
geom_point
geom_histogram
geom_bar
geom_boxplot
geom_density
geom_violin
geom_smooth
facet_grid
Ülesanded
1 Milline tehtud sammude jaotus? Millist geomeetrilist esitust
võib selle uurimiseks kasutada?
2 Milline on tehtud sammude jaotus sugude kaupa? Vihjed:
3 Kumma soo esindajad teevad mediaanis vähem sammusid?
4 Tee läbi see sama võrdlus vanusegruppide kaupa. Kas järeldus on
sama?
5 Vaata vanusegruppide arvukust sugude kaupa. Kas jaotus on
sarnane või erinev?
6 Kas vanuse ja tehtud sammude vahel on seos? Kas seos tundub
lineaarne?
7 Milline on seos kehamassi indeksi ja sammude vahel? Kas seos on
lineaarne ja või on tegu millegi keerukamaga?
#1
ggplot(bmi, aes(x = Steps)) +
geom_histogram()

ggplot(bmi, aes(x = Steps)) +
geom_histogram(bins = 100)

ggplot(bmi, aes(x = Steps)) +
geom_density()

ggplot(bmi, aes(x = Steps)) +
geom_boxplot()

#2
ggplot(bmi, aes(x = Steps, fill=Gender)) +
geom_histogram(position = "identity", alpha=0.3)

ggplot(bmi, aes(x = Steps, fill=Gender, color=Gender)) +
geom_histogram(position = "identity", alpha=0.3)

ggplot(bmi, aes(x = Steps, fill=Gender, color=Gender)) +
geom_density(position = "identity", alpha=0.3)

#3
ggplot(bmi, aes(x = Steps, y=Gender)) +
geom_boxplot()

#4
ggplot(bmi, aes(x = Steps, y=AgeGroup, fill=Gender)) +
geom_boxplot()

#5
ggplot(bmi, aes(x = Gender, fill=AgeGroup)) +
geom_bar()

ggplot(bmi, aes(x = Gender, fill=AgeGroup)) +
geom_bar(position="dodge")

ggplot(bmi, aes(x = Gender, fill=AgeGroup)) +
geom_bar(position="fill")

#6
ggplot(bmi, aes(x = Age, y=Steps)) +
geom_point() +
geom_smooth()

ggplot(bmi, aes(x = Age, y=Steps)) +
geom_point() +
geom_smooth(method = "lm")

#7
ggplot(bmi, aes(x = BMI, y=Steps)) +
geom_point() +
geom_smooth()

ggplot(bmi, aes(y = BMI, x=Steps)) +
geom_point() +
geom_smooth(method = "lm")

Kodune ülesanne
Failis ylevaatused.RData on andmestik kõigi Eestis toime
pandud sõidukite tehniliste ülevaatuste kohta. Tunnuste kohta lisainfot
palju pole, kuid nimed peaks suht selged olema. Andmestik pärineb eesti
avaandmete portaalist: https://avaandmed.eesti.ee/datasets/maismaasoidukite-tehnoulevaatused-eestis
Ülesandeks on selle andmestiku põhjal joonistada välja graafik mis
toob välja mingi huvitava seose. Andmestik on suur ja graafik ei pea
kajastama tervet andmestikku, vaid võib keskenduda mingile andmete
alamhulgale.
Sellel graafikul võib olla mitu paneeli, kuid peab olema siiski
üks fail, mis välja trükkides mahuks ühele lehele ja
oleks loetav. Kuna andmed on keerukad võib pildi salvestada suuremana,
kui Rstudio graafiku aknasse mahub (kasutades käsku ggsave
ja argumente height ja width), et kõigel
vajalikul piisavalt ruumi oleks.
Esitada tuleb graafikut genereeriv kood, põhjendus
miks just antud tüüpi graafik(ud) on nende andmete näitamiseks hea ja ka
mõne lauseline järeldus, mille te pildilt olete välja
lugenud.
Graafik peab vastama järgnevatele tingimustele.
Kasutatud on vähemalt 5 erinevat tunnust
Kasutatud on vähemalt 2 erinevat geom_* funktsiooni
On modifitseeritud graafiku elementide väljanägemist ning need
muudatused on asjakohased
On valitud andmetele sobiv visualiseerimise meetod
Graafik ei vaja lisaselgitusi ning on kergesti loetav (kõik
tekstid suurte algustähtedega, grammatiliselt korrektsed, piisavalt
kirjeldavad).
Tekstilised järeldused ja graafik lähevad kokku.
load("ylevaatused.RData", verbose = T)
Loading objects:
ylevaatused
ylevaatused
names(ylevaatused) # colnames(ylevaatused)
[1] "TEHNOYLEVAATUSPUNKT" "PUNKTI_KOOD" "TOOTAJA" "YV_KUUPAEV" "YLEVAATUSLIIK" "YLEVAATUSOTSUS" "RIKKED"
[8] "SOIDUK_ID" "ESMANE_REG_AASTA" "MARK" "MUDEL" "KATEGOORIA" "KERETYYP"
unique(ylevaatused$YLEVAATUSOTSUS)
[1] "KORRAS" "KORDUVALE" "VASTAB_NOUETELE" "SOITMISEKS_KOLBMATU" "KATKESTATUD" "EI_VASTA_NOUETELE"
str(ylevaatused)
Classes ‘spec_tbl_df’, ‘tbl_df’, ‘tbl’ and 'data.frame': 720032 obs. of 13 variables:
$ TEHNOYLEVAATUSPUNKT: chr "Narva Tehno OÜ (Lääne)" "A-Ülevaatus OÜ (Raua)" "Rehvikeskus OÜ" "PRO Tehno OÜ (Sauga)" ...
$ PUNKTI_KOOD : chr "NH" "DR" "LE" "FK" ...
$ TOOTAJA : chr "440" "631" "0807" "579" ...
$ YV_KUUPAEV : chr "2023-12" "2023-07" "2023-06" "2023-10" ...
$ YLEVAATUSLIIK : chr "KORRALINE" "KORRALINE" "KORRALINE" "KORRALINE" ...
$ YLEVAATUSOTSUS : chr "KORRAS" "KORRAS" "KORRAS" "KORRAS" ...
$ RIKKED : chr NA NA NA NA ...
$ SOIDUK_ID : num 1 2 3 4 5 6 7 8 9 10 ...
$ ESMANE_REG_AASTA : num 2003 2011 1996 2015 2018 ...
$ MARK : chr "FORD" "PANAV" "HONDA" "KRONE" ...
$ MUDEL : chr "GALAXY" "NS136" "VT 700C" "SDP 27ELB4-CS" ...
$ KATEGOORIA : chr "M1" "O4" "L3e" "O4" ...
$ KERETYYP : chr "MAHTUNIVERSAAL" "KALLUR" "MOOTORRATAS" "MADEL" ...
- attr(*, "spec")=List of 3
..$ cols :List of 13
.. ..$ TEHNOYLEVAATUSPUNKT: list()
.. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
.. ..$ PUNKTI_KOOD : list()
.. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
.. ..$ TOOTAJA : list()
.. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
.. ..$ YV_KUUPAEV : list()
.. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
.. ..$ YLEVAATUSLIIK : list()
.. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
.. ..$ YLEVAATUSOTSUS : list()
.. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
.. ..$ RIKKED : list()
.. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
.. ..$ SOIDUK_ID : list()
.. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
.. ..$ ESMANE_REG_AASTA : list()
.. .. ..- attr(*, "class")= chr [1:2] "collector_double" "collector"
.. ..$ MARK : list()
.. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
.. ..$ MUDEL : list()
.. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
.. ..$ KATEGOORIA : list()
.. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
.. ..$ KERETYYP : list()
.. .. ..- attr(*, "class")= chr [1:2] "collector_character" "collector"
..$ default: list()
.. ..- attr(*, "class")= chr [1:2] "collector_guess" "collector"
..$ delim : chr ","
..- attr(*, "class")= chr "col_spec"
- attr(*, "problems")=<externalptr>
library(tidyverse)
library(patchwork)
ylev <- ylevaatused %>%
mutate(
RIKKED = ifelse(is.na(RIKKED), "", RIKKED),
VIGADE_ARV = ifelse(RIKKED == "", 0, str_count(RIKKED, ";") + 1),
) %>%
filter(str_starts(KATEGOORIA, "M") & !is.na(KATEGOORIA)) %>%
mutate(KERETYYP_GRUPP = case_when(
KERETYYP %in% c("MAHTUNIVERSAAL", "UNIVERSAAL", "LUUKPÄRA", "SEDAAN",
"KUPEE", "LIMUSIIN", "KOMBI") ~ "Sõiduauto",
KERETYYP %in% c("LAHTINE", "PIKAP",
"SIHTOTSTARBELINE", "ERIOTSTARBELINE SÕIDUK") ~ "Kaubik / tööauto",
KERETYYP %in% c("MITMEOTSTARBELINE SÕIDUK") ~ "Mitmeotstarbeline",
KERETYYP %in% c("BUSS", "LIIGENDBUSS", "KORRUSBUSS", "TROLL") ~ "Buss",
KERETYYP %in% c("KIIRABI", "MATUSEAUTO", "ELAMU") ~ "Erisõiduk",
TRUE ~ NA
))
#sample_n(20000)
ylev
#unique(ylev$YLEVAATUSOTSUS)
unique(ylev$KERETYYP)
[1] "MAHTUNIVERSAAL" "UNIVERSAAL" "LAHTINE" "LUUKPÄRA" "SEDAAN"
[6] "ELAMU" "MITMEOTSTARBELINE SÕIDUK" "BUSS" "SIHTOTSTARBELINE" "KUPEE"
[11] "LIIGENDBUSS" "KIIRABI" "PIKAP" "ERIOTSTARBELINE SÕIDUK" "LIMUSIIN"
[16] "MATUSEAUTO" NA "KORRUSBUSS" "KOMBI" "TROLL"
# Vanus vs mitte_positiivne ülevaatusotsus (M1 ja m1g kategooria (sõiduuatod ja bussid))
library(scales)
palett = hue_pal()(8)
kategooria_värvid = c(
"M1" = palett[2],
"M1G" = palett[4],
"M2" = palett[6],
"M3" = palett[8]
)
m1_m1g <- ylev %>%
filter(!is.na(ESMANE_REG_AASTA), !is.na(YLEVAATUSOTSUS)) %>%
filter(YLEVAATUSOTSUS %in% c("EI_VASTA_NOUETELE", "SOITMISEKS_KOLBMATU")) %>%
filter(KATEGOORIA %in% c("M1", "M1G")) %>%
ggplot(aes(x = ESMANE_REG_AASTA, color = KATEGOORIA, fill = KATEGOORIA)) +
geom_density(alpha = 0.2) +
labs(
title = "Sõiduautod",
x = "Esmane registreerimse aasta",
y = "Tihedus",
fill = "Kategooria",
color = "Kategooria"
) +
theme_minimal(base_size = 12) +
theme(plot.title = element_text(face = "plain", size = 12)) +
scale_color_manual(values = kategooria_värvid) +
scale_fill_manual(values = kategooria_värvid)
m2_m3 <- ylev %>%
filter(!is.na(ESMANE_REG_AASTA), !is.na(YLEVAATUSOTSUS)) %>%
filter(YLEVAATUSOTSUS %in% c("EI_VASTA_NOUETELE", "SOITMISEKS_KOLBMATU")) %>%
filter(KATEGOORIA %in% c("M2", "M3")) %>%
ggplot(aes(x = ESMANE_REG_AASTA, color = KATEGOORIA, fill = KATEGOORIA)) +
geom_density(alpha = 0.2) +
labs(
title = "Bussid",
x = "Esmane registreerimse aasta",
y = "Tihedus",
fill = "Kategooria",
color = "Kategooria"
) +
theme_minimal(base_size = 12) +
theme(plot.title = element_text(face = "plain", size = 12)) +
scale_color_manual(values = kategooria_värvid) +
scale_fill_manual(values = kategooria_värvid)
graafik1 <- m1_m1g / m2_m3 +
plot_layout(guides = "collect") +
plot_annotation(
title = "Negatiivne ülevaatusotsus",
subtitle = "M-kategooria sõidukid",
#caption = "Allikas: ?? trust me bro",
theme = theme(
plot.title = element_text(face = "bold", size = 16),
plot.subtitle = element_text(size = 12)
)
)
#graafik1
# Auto kategooria ja vigade arv
graafik2 <- ylev %>%
filter(!is.na(KATEGOORIA), !is.na(KERETYYP_GRUPP)) %>%
group_by(KATEGOORIA) %>%
ggplot(aes(y = KATEGOORIA, x = VIGADE_ARV, color=KERETYYP_GRUPP)) +
geom_point(position = "jitter") +
labs(
title = "Vigade arv keretüübi kohta",
subtitle = "M-kategooria sõidukid",
y = "Keretüüp",
x = "Vigade Arv",
color = "Keretüüp"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 16),
plot.subtitle = element_text(size = 12)
)
#graafik2
graafik1 / graafik2 +
plot_layout(guides = "keep")

Ma tahtsin uurida järgnevat:
Mida vanem auto seda suurema tõenäosusega kukub ülevaatusel auto
läbi.
Sõiduautodel on tavaliselt rohkem vigu kui bussidel, kuna autosid
on rohkem teedel kui busse.
Järeldused:
sõiduautod: Mida vanem auto, seda suurem on tõenäosus ülevaatusel
läbi kukkuda.
Bussid: Vanus ei selgita otseslet läbikukkumist. Busside puhul mõjutab
tulemust pigem asutusintensiivsus (suurem aastane läbisõit), mistõttu
võivad ka uuemad bussid sagedamini läbi kukkuda.
Sõiduautodel on rohkem äärmuslikke vigade väärtusi, kuna
sõiduautosid on valimis tunduvalt rohkem kui busse. Valimi suurus
tekitab loomulikult suurema hajuvuse.
LS0tDQp0aXRsZTogIlByYWt0aWt1bSA4IC0gZ2dwbG90MiBqw6R0ayINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiMjIFNpc3NlanVoYXR1cw0KDQpTaWluIHByYWt0aWt1bWlzIGrDpHRrYW1lIGdncGxvdDIgdsO1aW1hbHVzdGUgw7VwcGltaXNlZ2EuIFNlbGxla3MsIGV0IHTDtsO2Z2EgcGlodGEgc2Fha3MgaGFrYXRhLCBsb2VtZSBzaXNzZSB2YWphbGlrdWQgcGFrZXRpZCBqYSBhbmRtZXN0aWt1Lg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KDQpsb2FkKCJsaW5uYWQuUkRhdGEiLCB2ZXJib3NlID0gVCkNCmBgYA0KDQojIyBGYWt0b3JpdGVnYSB0w7bDtnRhbWluZQ0KDQpQYWtldHQgZ2dwbG90MiDDvHJpdGFiIHbDtWltYWxpa3VsdCBwYWxqdSBrYXN1dGFkYSBqb29uaXN0YW1pc2VsIGluZm9ybWF0c2lvb25pIG1pcyBvbiBrb2RlZXJpdHVkIGZha3RvcmkgdGFzZW1ldGVzc2UuwqBGYWt0b3Igb24gYW5kbWV0w7zDvHAgZGlza3JlZXRzZXRlbGUgbXV1dHVqYXRlbGUsIG1pcyBzw6RpbGl0YWIgbGlzYWtzIHbDpMOkcnR1c3RlbGUga2EgaW5mbyBrw7xpZ2kgdsO1aW1hbGlrZSB2w6TDpHJ0dXN0ZSBuaW5nIG5lbmRlIGrDpHJqZXN0dXN0ZSBrb2h0YS4gRmFrdG9yaSB0YXNlbWUgbmltZWRlIHDDtWhqYWwgam9vbmlzdGF0YWtzZSBuw6RpdGVrcyBsZWdlbmQgamEgdGFzZW1lIGrDpHJqZXN0dXN0IGthc3V0YXRha3NlIHRlbGdlZGVsIGVsZW1lbnRpZGUgasOkcmplc3RhbWlzZWtzLiBTZWV0w7V0dHUgb24gb2x1bGluZSB0dW5kYSBwYWFyaSBuaXBwaSBrdWlkYXMgZmFrdG9yaXRlIHRhc2VtZXRlZ2EgdMO2w7Z0YWRhLsKgDQoNCkVzaXRla3Mgb24ga2FzdWxpayBwYW5uYSBmYWt0b3JpIHRhc2VtZXRlbGUgc2lzdWthZCBuaW1lZC4gU2VkYSBzYWFiIHRlaGEgYW5kZXMga8Okc3VsZSBgZmFjdG9yYCBldHRlIGp1YmEgc2lzdWthdGUgbmltZWRlZ2Egc8O1bmV2ZWt0b3JpLCBrYXN1dGFkZXMgYXJndW1lbnRpIGBsYWJlbHNgLg0KDQpgYGB7cn0NCmEgPSBmYWN0b3IoYygxLCAxLCAxLCAyLCAyLCAzKSwgbGFiZWxzID0gYygiQSIsICJCIiwgIkMiKSkNCmENCmBgYA0KDQpGYWt0b3JpIHRhc2VtZXRlIG5pbWVzaWQgc2FhYiBtdXV0YSBrYXN1dGFkZXMga8Okc2t1IGBmY3RfcmVjb2RlYCAodHVsZWIga2Fhc2EgYHRpZHl2ZXJzZWAgcGFrZXRpZ2EpLiBTZWxsZWdhIHNhYWIga2EgZmFrdG9yaSB0YXNlbWVpZCBrb2trdSB2w7V0dGEuDQoNCmBgYHtyfQ0KZmN0X3JlY29kZShhLCAiSSIgPSAiQSIsICJJSSIgPSAiQiIsICJJSUkiID0gIkMiKQ0KDQpmY3RfcmVjb2RlKGEsICJJIiA9ICJBIiwgIklJIiA9ICJCIikNCg0KZmN0X3JlY29kZShhLCAiSSIgPSAiQSIsICJJSSIgPSAiQiIsICJJIiA9ICJDIikNCmBgYA0KDQpGYWt0b3JpIHRhc2VtZXRlIGrDpHJqZXN0dXN0IHNhYWIgbXV1dGEga2Ega8Okc3VnYSBgZmN0X3JlbGV2ZWxgLCBrdXMgZXR0ZWFudHVkIHRhc2VtZWQgdMO1c3RldGFrc2UgasOkamVrb3JyYXMgZXR0ZSBwb29sZQ0KDQpgYGB7cn0NCmEgPSBmYWN0b3IoYygxLCAxLCAxLCAyLCAyLCAzKSwgbGFiZWxzID0gYygiQSIsICJCIiwgIkMiKSkNCmENCg0KZmN0X3JlbGV2ZWwoYSwgIkMiKQ0KZmN0X3JlbGV2ZWwoYSwgIkMiLCAiQiIsICJBIikNCmBgYA0KDQpLdWkgbWUgdGFoYW1lIG11dXRhIGZha3Rvcml0ZSBqw6RyamVrb3JkYSBtaW5naSB0ZWlzZSB2ZWt0b3JpIGrDpHJnaSwgc2lpcyBzYWFiIGthc3V0YWRhIGvDpHNrdSBgZmN0X3Jlb3JkZXJgLg0KDQpgYGB7cn0NCmEgPSBmYWN0b3IoYygxLCAxLCAxLCAyLCAyLCAzKSwgbGFiZWxzID0gYygiQSIsICJCIiwgIkMiKSkNCmIgPSBjKDEsIDUsIDYsIDIsIC00LCAxMCkNCmENCmINCg0KZmN0X3Jlb3JkZXIoYSwgYikNCmZjdF9yZW9yZGVyKGEsIGIsIC5kZXNjID0gVCkNCmZjdF9yZW9yZGVyKGEsIGIsIC5mdW4gPSBtYXgpDQoNCmBgYA0KDQpTZWVnYSBrdWkgbWUgdGFoYW1lIG11Z2FuZGFkYSBwaWx0aSBvbiB0aWh0aXBlYWxlIGthc3VsaWt1bSBlbm5lIG11Z2FuZGFkYSBhbmRtZWlkIGphIHNpaXMgbmVuZGVnYSBwaWx0IGpvb25pc3RhZGEuDQoNCmBgYHtyfQ0KZ2dwbG90KGxpbm5hZCwgYWVzKHggPSBwZXJfY2FwaXRhX2luYywgeSA9IHVuZW1wbG95bWVudF9yYXRlLCBjb2xvdXIgPSBpbmNvbWVfY2xhc3MpKSArDQogIGdlb21fcG9pbnQoKSANCg0KbGlubmFkICU+JSANCiAgbXV0YXRlKGluY29tZV9jbGFzcyA9IGZjdF9yZWNvZGUoaW5jb21lX2NsYXNzLCAiSGlnaCIgPSAiVmVyeSBIaWdoIiwgIkxvdyIgPSAiVmVyeSBMb3ciLCAiTG93IiA9ICJNZWRpdW0iKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBwZXJfY2FwaXRhX2luYywgeSA9IHVuZW1wbG95bWVudF9yYXRlLCBjb2xvdXIgPSBpbmNvbWVfY2xhc3MpKSArDQogICAgZ2VvbV9wb2ludCgpIA0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGxpbm5hZCwgYWVzKHggPSBwZXJfY2FwaXRhX2luYywgeSA9IHVuZW1wbG95bWVudF9yYXRlLCBjb2xvdXIgPSBQb3ZlcnR5X2ZhY3RvcikpICsNCiAgZ2VvbV9wb2ludCgpIA0KDQpsaW5uYWQgJT4lIA0KICBtdXRhdGUoUG92ZXJ0eV9mYWN0b3IgPSBmY3RfcmVsZXZlbChQb3ZlcnR5X2ZhY3RvciwgIkxvdyIsICJNZWRpdW0iLCAiSGlnaCIpKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IHBlcl9jYXBpdGFfaW5jLCB5ID0gdW5lbXBsb3ltZW50X3JhdGUsIGNvbG91ciA9IFBvdmVydHlfZmFjdG9yKSkgKw0KICBnZW9tX3BvaW50KCkgDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QobGlubmFkLCBhZXMoeCA9IENvdW50eSwgeSA9IHBvcF9lc3RpbWF0ZSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpIA0KDQpsaW5uYWQgJT4lIA0KICBtdXRhdGUoQ291bnR5ID0gZmN0X3Jlb3JkZXIoQ291bnR5LCBwb3BfZXN0aW1hdGUpKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IENvdW50eSwgeSA9IHBvcF9lc3RpbWF0ZSkpICsNCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgDQpgYGANCg0KIyMjIyDDnGxlc2FuZGVkDQoNCi0gICBKb29uaXN0YWdlIHNlb3MgKmJhY2hlbG9yKiBqYSAqaGlnaF9zY2wqIHZhaGVsIG5pbmcgbsOkaWRha2UgdsOkcnZpZ2EgdHVubnVzdCAqaW5jb21lX2NsYXNzKiAuIFbDtXRhIGtva3Uga2xhc3NpZCAiVmVyeSBMb3ciIGphICJMb3ciIG5pbmcgdXVkYSB2w6RydmlkZSBqw6RyamVrb3JkIG5paSwgZXQgc2VlIGFsZ2FrcyB2w6RnYSBrw7VyZ2VzdCBqYSBsw7VwcGVrcyBtYWRhbGFnYS4NCg0KYGBge3J9DQoNCmxpbm5hZCAlPiUgDQogIG11dGF0ZShpbmNvbWVfY2xhc3MgPSBmY3RfcmVjb2RlKGluY29tZV9jbGFzcywgIkxvdyIgPSAiVmVyeSBMb3ciKSkgJT4lDQogIG11dGF0ZShpbmNvbWVfY2xhc3MgPSBmY3RfcmVsZXZlbChpbmNvbWVfY2xhc3MsICJMb3ciLCAiTWVkaXVtIiwgIkhpZ2giLCAiVmVyeSBIaWdoIiApKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IGJhY2hlbG9yICwgeSA9IGhpZ2hfc2NsICwgY29sb3VyID0gaW5jb21lX2NsYXNzICkpICsNCiAgZ2VvbV9wb2ludCgpIA0KYGBgDQoNCiMjIEdyYWFmaWt1dGUgYW5ub3RlZXJpbWluZSBqYSBtdWdhbmRhbWluZQ0KDQojIyMgR3JhYWZpa3V0ZSBhbm5vdGVlcmltaW5lDQoNClRlbGdlZGUgamEgZ3JhYWZpa3UgYW5ub3RlZXJpbWlzZSB2aWlzZSBtZSBvbGVtZSBqdWJhIHTDtsO2IGvDpGlndXMgbsOkaW51ZC4gUGFsanVkIGFzamFkIHNhYWIgw6RyYSBsYWhlbmRhZGEgZXJpbmV2YXRlIHNrYWxlZXJpbWlzZnVua3RzaW9vbmlkZSBwYXJhbWVldHJpdGVnYS4gU2lpc2tpIG9uIHBhbGp1ZGVsZSBuZWlzIG9sZW1hcyBrYSBtdWdhdmFtYWQgdmFzdGVkIGVyYWxkaSBmdW5rdHNpb29uaWRlZ2EgbWlzIGhvaWF2YWQgdHLDvGtraW1pc3Qga29ra3UuIE5laXN0IG9sdWxpc2VtYWQgb27CoA0KDQotICAgYGdndGl0bGUoKWAgLSBtw6TDpHJhbWUgZ3JhYWZpa3UgcGVhbGtpcmphDQoNCi0gICBgeGxhYigpYCwgYHlsYWIoKWAgLSB0ZWxnZWRlIHBlYWxraXJqYWQNCg0KLSAgIGB4bGltKClgLCBgeWxpbSgpYCAtIHRlbGdlZGUgdsOkw6RydHVzdmFoZW1pa3UgbcOkw6RyYW1pbmUNCg0KIyMjIEdyYWFmaWt1dGUgc3RpaWwNCg0KVmFoZXN0IG9uIHZhamEgbXV1dGEgYGdncGxvdDJgIGdyYWFmaWt1dGUgw7xsZcO8bGRpc3Qgc3RpaWxpIHbDtWkgbcO1bmUgZWxlbWVuZGkgdsOkbGphbsOkZ2VtaXN0LiBOw6RpdGVrcyBvbiBzdGFuZGFyZG5lIGBnZ3Bsb3QyYCBncmFhZmlrdXRlIHRhdXN0IGhhbGwsIG1pcyBlaSBvbGUgYWxhdGkgcGFyaW0gbGFoZW5kdXMuIFNlZGEgb24gbGlodG5lIG11dXRhIGvDpHN1Z2EgYHRoZW1lX2J3YCBtaXMgdGVlYiB0YXVzdGEgdmFsZ2VrcyBqYSBtdXVkYWIga2EgcG9ydHN1IG11dWRlIGdyYWFmaWt1IGVsZW1lbnRpZGUgdsOkcnZlIGphIGt1anUuDQoNCmBgYHtyfQ0KZ2dwbG90KGxpbm5hZCwgYWVzKHggPSBwZXJfY2FwaXRhX2luYywgeSA9IHVuZW1wbG95bWVudF9yYXRlLCBjb2xvdXIgPSBiaXJ0aF9jbGFzcykpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgdGhlbWVfYncoKSANCmBgYA0KDQpOZWlkIGZ1bmt0c2lvb25lIG9uIHZlZWwsIHRhc3ViIHZhYWRhdGEgbWlkYSBSU3R1ZGlvIHBha3ViLCBrdWkga2lyanV0YWRhIGFsZ3VzIGB0aGVtZV9gIC4gVmVlbCByb2hrZW0gZXJpbmV2YWlkIHRlZW1hc2lkIG9uIG9sZW1hcyBwYWtldGlzIGBnZ3RoZW1lc2AgKDxodHRwczovL3l1dGFubmloaWxhdGlvbi5naXRodWIuaW8vYWxsWW91ckZpZ3VyZUFyZUJlbG9uZ1RvVXMvZ2d0aGVtZXMvPikuDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3RoZW1lcykNCmdncGxvdChsaW5uYWQsIGFlcyh4ID0gcGVyX2NhcGl0YV9pbmMsIHkgPSB1bmVtcGxveW1lbnRfcmF0ZSwgY29sb3VyID0gYmlydGhfY2xhc3MpKSArDQogIGdlb21fcG9pbnQoKSArDQogIHRoZW1lX3dzaigpIA0KYGBgDQoNClTDpHBzZW1hbHQgc2FhYiBtdXV0YSBrb25rcmVldHNlaWQgZWxlbWVudGUga8Okc3VnYSBgdGhlbWVgLiBTaWluIG9uIHRlcnZlIHBvcnRzIHBhcmFtZWV0cmVpZCBtaXMgdMO2w7Z0YXZhZCBoaWVyYXJoaWxpc2VsdC4gT2x1bGlzZW1hZCBvbiB0b29kdWQgasOkcmdtaXNlbCBqb29uaXNlbC4NCg0KIVshW10oaW1hZ2VzL2NsaXBib2FyZC05NzkzMzc1MDMucG5nKV0oaW1hZ2VzL1NjcmVlbnNob3QlMjAyMDIxLTAyLTIyJTIwYXQlMjAxMC41NC4xOC5wbmcpDQoNCk5lbmRlbGUgc2FhYnbDpMOkcnR1c2VrcyBhbmRhIGvDpHNrZSBgZWxlbWVudF90ZXh0YCwgYGVsZW1lbnRfbGluZWAgamEgYGVsZW1lbnRfcmVjdGAgdmFzdGF2YWx0IHBhcmFtZWV0cmkgdMO8w7xiaWxlLiBLw6Rza3VkZSBgZWxlbWVudF8qYCBwYXJhbWVldHJpZCB2YXN0YXZhZCBzdWh0ZWxpc2VsdCB0w6Rwc2VsdCBzYXJuYXN0ZSBlbGVtZW50aWRlIGdyaWQgcGFrZXRpcyBrYXN1dGF0YXZhdGVsZSBwYXJhbWVldHJpdGVsZS4gT2x1bGluZSBmdW5rdHNpb29uIG9uIGthIGVsZW1lbnRfYmxhbmsgbWlzIHZhc3RhdmEgZWxlbWVuZGkgbGlodHNhbHQgw6RyYSBrdXN0dXRhYi4NCg0KYGBge3J9DQpnZ3Bsb3QobGlubmFkLCBhZXMoeCA9IHBlcl9jYXBpdGFfaW5jLCB5ID0gdW5lbXBsb3ltZW50X3JhdGUsIGNvbG91ciA9IGJpcnRoX2NsYXNzKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAicGluayIpLCBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQ0KYGBgDQoNClbDpGdhIG9sdWxpbmUgcGFyYW1lZXRlciBrw6RzdXMgdGhlbWUgb24ga2EgYGxlZ2VuZC5wb3NpdGlvbmAuIEt1aSBzZWxsZSB2w6TDpHJ0dXNla3Mgb24gYCJub25lImAga3VzdHV0YXRha3NlIGxlZ2VuZCDDpHJhLiBWw6TDpHJ0dXNlZCBgImxlZnQiYCwgYCJyaWdodCJgLCBgInRvcCJgIGphIGAiYm90dG9tImAga8OkaXR1dmFkIG5hZ3UgdsO1aWtzIG9vZGF0YSAuIEFuZGVzIGV0dGUga2FoZSBlbGVtZW5kaWxpc2UgdmVrdG9yaSBwYWlndXRhYiB0YSBsZWdlbmRpIGdyYWFmaWt1IGFsYSBzZWVzIHZhc3RhdmFsdCBhbnR1ZCBrb29yZGluYWF0aWRlbGUsIHBhcmFsbGVlbHNlbHQgb24gaGVhIGthc3V0YWRhIGthIGBsZWdlbmQuanVzdGlmaWNhdGlvbmAgYXJndW1lbnRpLCBtaXMgdsO1aW1hbGRhYiBsZWdlbmRpIHBhaWd1dHVzdCB0w6Rwc2VtYWx0IGtvbnRvbGxpZGEuDQoNCmBgYHtyfQ0KZ2dwbG90KGxpbm5hZCwgYWVzKHggPSBwZXJfY2FwaXRhX2luYywgeSA9IHVuZW1wbG95bWVudF9yYXRlLCBjb2xvdXIgPSBiaXJ0aF9jbGFzcykpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGxpbm5hZCwgYWVzKHggPSBwZXJfY2FwaXRhX2luYywgeSA9IHVuZW1wbG95bWVudF9yYXRlLCBjb2xvdXIgPSBiaXJ0aF9jbGFzcykpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QobGlubmFkLCBhZXMoeCA9IHBlcl9jYXBpdGFfaW5jLCB5ID0gdW5lbXBsb3ltZW50X3JhdGUsIGNvbG91ciA9IGJpcnRoX2NsYXNzKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDEsMSksIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygxLCAxKSkNCmBgYA0KDQojIyMjIMOcbGVzYW5kZWQNCg0KLSAgIFByb292aSBzYWF2dXRhZGEgdW1iZXMgasOkcmdtaW5lIHBpbHQuDQoNCiFbXShpbWFnZXMvU2NyZWVuc2hvdCUyMDIwMjEtMDItMjglMjBhdCUyMDE2LjMxLjU0LnBuZykNCg0KYGBge3J9DQpnZ3Bsb3QobGlubmFkLCBhZXMoeCA9IGJhY2hlbG9yLCB5ID0gaGlnaF9zY2wsIGNvbG91ciA9IGluY29tZV9jbGFzcykpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgc2NhbGVfY29sb3JfYnJld2VyKHR5cGU9ImRpdiIsIHBhbGV0dGU9MikgKw0KICBnZ3RpdGxlKCJIaWdoIFNjaG9vbCBhbmQgSGlnaGVyIEVkdWNhdGlvbiIpICsNCiAgdGhlbWUoDQogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdvbGQiKSwNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gYygxLDApLCANCiAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMSwgMCksDQogICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAiYmxhY2siKSwNCiAgICBsZWdlbmQua2V5ID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JleTk1IikNCiAgKQ0KYGBgDQoNCiMjIEdyYWFmaWt1dGUgc2FsdmVzdGFtaW5lDQoNCkdyYWZpa3VpZCBzYWFiIHNhbHZlc3RhZGEga8Okc3VnYSBgZ2dzYXZlKClgLCBLdWkgZXR0ZSBhbmRhIHZhaWQgZmFpbGkgbmltaSwgc2lpcyBzYWx2ZXN0YWIgc2VlIGvDpHNrIHZpaW1hc2UgZ3JhYWZpa3UsIG1pcyBzYWkgam9vbmlzdGF0dWQsIGt1c2p1dXJlcyBzdXVydXNlIHbDtXRhYiB0YSBha25hIGrDpHJnaSBuaW5nIGZhaWxpdMO8w7xiaSBtw6TDpHJhYiBmYWlsaSBuaW1lIGxhaWVuZGkgasOkcmdpLg0KDQpQYXJhbWVldHJlaWQgYHdpZHRoYCBqYSBgaGVpZ2h0YCBrYXN1dGFkZXMgb24gdsO1aW1hbGlrIMOkcmEgbcOkw6RyYXRhIGthIHTDpHBzZWx0IGpvb25pc2UgbcO1w7VkdWQgKHRvbGxpZGVzKS4NCg0KYGBge3J9DQpnZ3Bsb3QobGlubmFkLCBhZXMoeCA9IHBlcl9jYXBpdGFfaW5jLCB5ID0gdW5lbXBsb3ltZW50X3JhdGUsIGNvbG91ciA9IFBvdmVydHlfZmFjdG9yKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDEsMSksIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygxLCAxKSkNCg0KZ2dzYXZlKCJwbG90MS5wbmciKQ0KZ2dzYXZlKCJwbG90MS5wZGYiKQ0KZ2dzYXZlKCJwbG90MV93aWRlLnBuZyIsIHdpZHRoID0gMTAsIGhlaWdodCA9IDUpDQpgYGANCg0KU29vdml0YXYgb24gc2FsdmVzdGFkYSBqb29uaXNlaWQgLnBkZiBmb3JtYWFkaXMuIE5paSB0ZWhha3NlIHZla3RvcmdyYWFmaWthIGphIHBpbHQgb24gYWxhdGkgaGVhIGt2YWxpdGVlZGlnYS4gS3VpIHNvb3ZpZGEgKFdpbmRvd3NpbCksIGV0IGthcyByYXN0ZXIga3VqdWwgc2FsdmVzdGF0dWQgcGlsZGlkIG7DpGl0ZWtzIC5wbmcgZmFpbGlkIGhlYWQgdsOkbGphIG7DpGVrc2lkIHRhc3ViIG11dXRhIHZhaWtpbWlzaSBncmFhZmlrYSBtb290b3JpdCBSU3R1ZGlvcyBqw6RyZ25ldmFsdC4NCg0KIVtdKGltYWdlcy9pbWFnZS5wbmcpDQoNCiMjIEVyaW5ldmF0ZSBncmFhZmlrdXRlIGtva2t1IHBhbmVtaW5lDQoNCkdyYWFmaWt1dGUgdGFoa3VkZWtzIGphZ2FtaW5lIHRvaW1pYiB2w6RnYSBow6RzdGksIGt1aSBtZSB0YWhhbWUgw7xodGUgdMO8w7xwaSBncmFhZmlrdXQgamFnYWRhIG1pdG1la3MuIEt1aWQga3VpIG1lIHRhaGFtZSBlcmluZXZhdCB0w7zDvHBpIGdyYWFmaWt1aWQgZXJpbmV2YXRlbCBtdXV0dWphdGVsIHNhbWFsIHBpbGRpbCBrw7VydnV0aSBuw6RpZGF0YSwgc2lpcyBzYW1hIGzDpGhlbmVtaW5lIGVpIHTDtsO2dGEuIFNpaW4gdHVsZXZhZCBhcHBpIGxpc2FwYWtldGlkLiBOw6RpdGVrcyBgcGF0Y2h3b3JrYCBvbiDDvGtzIG1pcyB2w7VpbWFsZGFiIGBnZ3Bsb3QyYCBncmFhZmlrdWlkIGtva2t1IHBhbm5hLg0KDQpFbm5lLCBrdWkgbMOkaGVtZSBgcGF0Y2h3b3JrYC1pIGVuZGEganV1cmRlIHZhYXRhbWUgw7xodGUga2FzdWxpa2t1IG5pcHBpLiBOaW1lbHQgb24gdsO1aW1hbGlrIGdncGxvdCBncmFhZmlrIG11dXR1amFuYSBzYWx2ZXRhZGEuIEpvb25pc3RhdGFrc2Ugc2VlIGFsbGVzIHNpaXMga3VpIG11dXR1amEgdsOkw6RydHVzIG9uIHZhamEgdsOkbGphIHRyw7xra2lkYS4NCg0KYGBge3J9DQpwID0gZ2dwbG90KGxpbm5hZCwgYWVzKHggPSBwZXJfY2FwaXRhX2luYywgeSA9IHVuZW1wbG95bWVudF9yYXRlLCBjb2xvdXIgPSBQb3ZlcnR5X2ZhY3RvcikpICsNCiAgZ2VvbV9wb2ludCgpDQoNCnANCnAgKyB0aGVtZV9idygpDQpgYGANCg0KTG9lbWUgc2lzc2UgcGFrZXRpIHBhdGNod29yayBqYSBkZWZpbmVlcmltZSBrb2xtIGdyYWFmaWt1dCBtaWRhIGtvbWJpbmVlcmltYSBoYWthdGEuDQoNCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcygicGF0Y2h3b3JrIikNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkocGF0Y2h3b3JrKQ0KDQpwMSA9IGdncGxvdChsaW5uYWQsIGFlcyh4ID0gcGVyX2NhcGl0YV9pbmMpKSArDQogIGdlb21faGlzdG9ncmFtKCkgKw0KICBnZ3RpdGxlKCJQbG90IDEiKQ0KcDIgPSBnZ3Bsb3QobGlubmFkLCBhZXMoeCA9IHBlcl9jYXBpdGFfaW5jLCB5ID0gdW5lbXBsb3ltZW50X3JhdGUsIGNvbG91ciA9IFBvdmVydHlfZmFjdG9yKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZ3RpdGxlKCJQbG90IDIiKQ0KcDMgPSBnZ3Bsb3QobGlubmFkLCBhZXMoeCA9IFN0YXRlLCB5ID0gdW5lbXBsb3ltZW50X3JhdGUsIGZpbGwgPSBTdGF0ZSkpICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICBnZ3RpdGxlKCJQbG90IDMiKQ0KDQoNCnAxDQpwMg0KcDMNCmBgYA0KDQpQYXRjaHdvcmtpcyB0ZWhha3NlIGthIGdyYWFmaWt1dGVnYSAidGVodGVpZCIuIFNlbGxla3MsIGV0IGdyYWFmaWt1aWQga8O1cnZ1dGkgcGFubmEgb24gdGVoZSBgfGAuDQoNCmBgYHtyfQ0KcDEgfCBwMiAgDQpgYGANCg0Kw5xrc3RlaXNlIGFsbGEgc2FhYiBwYW5uYSBncmFhZmlrdWlkIHRlaHRlZ2EgYC9gIC4NCg0KYGBge3J9DQpwMS9wMg0KYGBgDQoNClRlaHRlaWQgc2FhYiBrYSBrb21iaW5lZXJpZGEsIHNpaXMgdHVsZWIgdMOkaGVsZXBhbnUganVodGlkYSB0ZWhldGUgasOkcmpla29ycmFsZQ0KDQpgYGB7cn0NCnAxIHwgcDIgLyBwMw0KYGBgDQoNCmBgYHtyfQ0KKHAxIHwgcDIpIC8gcDMNCmBgYA0KDQpTZWxsZWtzLCBldCBwaWx0aWRlIHBhaWd1dHVzdCBwYXJlbWluaSBrb250cm9sbGlkYSBvbiBmdW5rdHNpb29uIGBwbG90X2xheW91dGAsIG1pbGxlZ2Egc2FhYiBqb29uaXNlIGVyaW5ldmFpZCBhc3Bla3RlIG11dXRhLiBOw6RpdGVrcyBgaGVpZ2h0c2AgcGFyYW1lZXRlciB2w7VpbWFsZGFiIG11dXRhIHBpbHRpZGUgc3VodGVsaXNpIGvDtXJndXNlaWQuDQoNCmBgYHtyfQ0KcDEgLyBwMiAvIHAzICsgcGxvdF9sYXlvdXQoaGVpZ2h0cyA9IGMoMiwgMiwgNCkpDQpgYGANCg0KQXJndW1lbnQgd2lkdGhzIHTDtsO2dGFiIHNhbWEgbW9vZGkuDQoNCmBgYHtyfQ0KKHAxIHwgcDIgfCBwMykgKyBwbG90X2xheW91dCh3aWR0aHMgPSBjKDIsIDIsIDQpKQ0KYGBgDQoNCkVlbG1pbmUgcGlsdCBqw6RpIGtvbGUgc2VzdCB2YXN0YXZhdGUgbGFpdXN0ZWdhIG9uIGdyYWFmaWt1dGUgYW5kbWVpZCBuw6RpdGF2YWQgcGFuZWVsaWQuIEt1bmEga2FoZWwgZ3JhYWZpa3VsIG9uIGFnYSBsZWdlbmQsIHNpaXMgbmVuZGUgbGFpdXN0IGFydmVzc2UgZWkgdsO1ZXRhLiBLw7xsbCBhZ2Egb24gdsO1aW1hbGlrIGFyZ3VtZW5kaWdhIGd1aWRlcyBrw7Vpa2lkZWx0IHBpbHRpZGVsdCBsZWdlbmRpZCBrb2trdSBrb2d1ZGEuDQoNCmBgYHtyfQ0KKHAxIHwgcDIgfCBwMykgKyBwbG90X2xheW91dCh3aWR0aHMgPSBjKDIsIDIsIDQpLCBndWlkZXMgPSAiY29sbGVjdCIpDQpgYGANCg0KUGFrZXRpcyBwYXRjaHdvcmsgb24gdmVlbCBwYWxqdSB2w7VpbWFsdXNpIGphIHRhc3ViIHV1cmlkYSBwYWtldGkga29kdWxlaHRlIDxodHRwczovL2dpdGh1Yi5jb20vdGhvbWFzcDg1L3BhdGNod29yaz4gamEgc2VhbCB2aWlkYXR1ZCDDtXBldHVzaS4NCg0KIyMjIyDDnGxlc2FuZGVkDQoNCi0gICBQcm9vdmlnZSB0ZWtpdGFkYSBqw6RyZ25ldiBwaWx0DQoNCiFbXShpbWFnZXMvU2NyZWVuc2hvdCUyMDIwMjEtMDItMjglMjBhdCUyMDE2LjE4LjIyLnBuZykNCg0KYGBge3J9DQoocDEgLyAoIHAyIHwgcDMpKSArIHBsb3RfbGF5b3V0KHdpZHRocyA9IGMoMiwgMiwgNCksIGd1aWRlcyA9ICJjb2xsZWN0IikNCmBgYA0KDQojIyBLb2R1bmUgw7xsZXNhbm5lDQoNCi0gICBQcm9vdmkgam9vbmlzdGFkYSB2w7VpbWFsaWt1bHQgc2FybmFuZSBncmFhZmlrIGrDpHJnbmV2YWdhLiBTaWluIG9uIHJha2VuZGF0dWQgdGVydmUgaHVsayBuaXBwZSwgbWlkYSBzYWkgc2VsbGVzIGphIGVlbG1pc2VzIHByYWtzaXMgw7VwaXR1ZC4gUHVua3RpZCBrdWp1bmV2YWQgc2VsbGUgcMO1aGphbCBrdWkgcGFsanUgbmVpc3QgbmlwcGlkZXN0IG9uIHJha2VuZGF0dWQuIEt1aSDDtWlnZXQgbmlwcGkgb24gcmFrZW5kYXR1ZCwga3VpZCB0dWxlbXVzIHBvbGUgdMOkcHNlbHQgaWRlbnRuZSwgc2lpcyBwdW5rdGUgbWFoYSBlaSB2w7V0YS4gTsOkaXRla3Mga3VpIHbDpHJ2IHBvbGUgdMOkcHNlbHQgw7VpZ2UgYWdhIMO1aWdlbCBncmFhZmlrdSBvc2FsIG9uIHNlZGEgc2lpc2tpIG11dWRldHVkLg0KDQogICAgIVtdKGltYWdlcy9TY3JlZW5zaG90JTIwMjAyMi0wOS0yMCUyMGF0JTIwMjIuMzkuMTclMjAxLnBuZykNCg0KYGBge3J9DQpsaW5uYWQNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHBhdGNod29yaykNCg0KDQpmaWxsX2NvbHMgPC0gYygNCiAgIkxvdyIgICAgPSAiI2Y0YTE0MiIsDQogICJNZWRpdW0iID0gImdyYXk5MCIsDQogICJIaWdoIiAgID0gIiM3YjY3YzgiDQopDQoNCm91dGxpbmVfY29scyA8LSBjKA0KICAiTG93IiAgICA9ICIjZTY1MDAwIiwNCiAgIk1lZGl1bSIgPSAiI2U2NTAwMCIsDQogICJIaWdoIiAgID0gIiNlNjUwMDAiDQopDQoNCg0KZGF0YSA8LSBsaW5uYWQgJT4lIA0KICBtdXRhdGUoDQogICAgaW5jb21lX2NsYXNzID0gZmN0X3JlY29kZShpbmNvbWVfY2xhc3MsICJIaWdoIiA9ICJWZXJ5IEhpZ2giLCAiTG93IiA9ICJWZXJ5IExvdyIpLA0KICAgIFBvdmVydHlfZmFjdG9yID0gZmN0X3JlbGV2ZWwoUG92ZXJ0eV9mYWN0b3IsICJMb3ciLCAiTWVkaXVtIiwgIkhpZ2giKSwNCiAgICBCaXJ0aF9mYWN0b3IgPSBmY3RfcmVsZXZlbChCaXJ0aF9mYWN0b3IsICJMb3ciLCAiTWVkaXVtIiwgIkhpZ2giKSANCiAgKQ0KDQpwMSA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBCaXJ0aF9mYWN0b3IsIHkgPSBvdmVyNjUsIGZpbGwgPSBCaXJ0aF9mYWN0b3IpKSArIA0KICAgIGdlb21fYm94cGxvdChmaWxsID0gTkEsIGNvbG9yPSJncmF5NSIpICsNCiAgICBnZW9tX3Zpb2xpbigNCiAgICAgIGFlcyhjb2xvciA9IEJpcnRoX2ZhY3RvciksDQogICAgIGFscGhhID0gMC40LCBsaW5ld2lkdGggPSAwLA0KICAgICAgZHJhd19xdWFudGlsZXMgPSBOVUxMDQogICAgKSArDQogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gZmlsbF9jb2xzKSArDQogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IG91dGxpbmVfY29scykgKw0KICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEyLjUsIGxpbmV0eXBlID0gImRvdHRlZCIpICsNCiAgICBmYWNldF93cmFwKH4gU3RhdGUsIG5jb2wgPSAzKSArIA0KICAgIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEzKSArDQogICAgdGhlbWUoDQogICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI2YyYjBjNCIsIGNvbG9yID0gImJsYWNrIiksDQogICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpLA0KICAgICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIsIGNvbG9yID0gTkEpLA0KICAgICAgbGVnZW5kLnBvc2l0aW9uID0gYygxLCAtMC4xKSwgDQogICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMSwgMCksDQogICAgICBsZWdlbmQua2V5ID0gZWxlbWVudF9yZWN0KCBjb2xvcj0icmVkIiksDQogICAgKSANCg0KDQoNCnAyIDwtIGdncGxvdChsaW5uYWQsIGFlcyh4ID0gZGVhdGhzLCB5ID0gYmlydGhzKSkgKw0KICBnZW9tX3BvaW50KGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDIsKSArDQogIGdlb21fc21vb3RoKGNvbG9yID0gInJlZCIsIGxpbmV3aWR0aCA9IDEpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgdGhlbWUoDQogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImJsYWNrIiwgY29sb3IgPSAiYmxhY2siKSwNCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG9yID0gIndoaXRlIiwgbGluZXR5cGUgPSAiZGFzaGVkIiksDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJ3aGl0ZSIsIGxpbmV0eXBlID0gImRhc2hlZCIpLA0KICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJibGFjayIpLA0KICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3IgPSAiYmxhY2siKSwNCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIsIGNvbG9yID0gIndoaXRlIiksDQogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApDQogICkgKw0KICAgIHNjYWxlX3hfY29udGludW91cyhuYW1lID0gIkhpZ2hlciBlZHVjYXRpb24gcGVyY2VudGFnZSIsIGJyZWFrcyA9IGMoMCwgMC41LCAxLCAxLjUsIDIpKSsNCiAgbGFicyh4ID0gImRlYXRocyIsIHkgPSAiYmlydGhzIikNCg0KDQpwMSAvIHAyICsgcGxvdF9sYXlvdXQoaGVpZ2h0cyA9IGMoMywgMSkpDQpgYGANCg0KIyMgZ2dwbG90Mi1nYSBncmFhZmlrdXRlIGpvb25pc3RhbWlzZSBoYXJqdXRhbWluZQ0KDQpTZWxsZSBqYSBlZWxtaXNlIHByYWt0aWt1bWkgcMO1aGphbCBwZWFrcyBvbHVsaXNlbWFkIG9za3VzZWQgZ2dwbG90MiBrYXN1dGFtaXNla3Mgb2xlbWFzIG9sZW1hLiBOw7zDvGQgcHJvb3ZpbWUgbmVpZCByYWtlbmRhZGEsIGthc3V0YWRlcyBrYSB0ZWFkbWlzaSB0ZWlzZXN0IGxvZW5ndXN0LCBrdXMgc2FpIHR1dHZ1c3RhdHVkIGdyYWFmaWt1dGUgdmFsaW1pc2UgcMO1aGltw7V0dGVpZCB0w6Rwc2VtYWx0Lg0KDQpMb2VtZSBzaXNzZSBrw7VpZ2VwZWFsdCBhbmRtZXN0aWt1LCBtaXMga2lyamVsZGFiIHNpaXMgMjAwMCBpbmltZXNlIGtlaGFtYXNzaSBpbmRla3NlaWQgamEganVodXNsaWt1bCBww6RldmFsIHRlaHR1ZCBzYW1tdWRlIGFydnUuIElnYSBpbmltZXNlIGtvaHRhIG9uIGthIGFudHVkIHN1Z3UsIHZhbnVzIGphIHZhbnVzZWdydXBwLiBMb2VtZSBhbmRtZXN0aWt1IHNpc3NlLg0KDQpgYGB7cn0NCmxvYWQoImJtaS5SRGF0YSIsIHZlcmJvc2UgPSBUKQ0KDQpibWkNCmBgYA0KDQpJZ2Egw7xsZXNhbmRlIHB1aHVsIHRhc3ViIHByb292aWRhIGVyaW5ldmFpZCB2YXJpYW50ZSBqYSBtw7VlbGRhIG1pbGxpbmUgdMO2w7Z0YWIgYW50dWQgb2x1a29ycmFzIHBhcmVtaW5pIGphIG1pa3MuIE1lZWxkZXR1bGV0dXNla3MsIHNpaW4gb24gb2x1bGlzZW1hZCBrw6RzdWQgbWlkYSB2YWphIHbDtWliIG1pbm5hDQoNCi0gICBgZ2VvbV9wb2ludGANCg0KLSAgIGBnZW9tX2hpc3RvZ3JhbWANCg0KLSAgIGBnZW9tX2JhcmANCg0KLSAgIGBnZW9tX2JveHBsb3RgDQoNCi0gICBgZ2VvbV9kZW5zaXR5YA0KDQotICAgYGdlb21fdmlvbGluYA0KDQotICAgYGdlb21fc21vb3RoYA0KDQotICAgYGZhY2V0X2dyaWRgDQoNCiMjIyMgw5xsZXNhbmRlZA0KDQotICAgMSBNaWxsaW5lIHRlaHR1ZCBzYW1tdWRlIGphb3R1cz8gTWlsbGlzdCBnZW9tZWV0cmlsaXN0IGVzaXR1c3QgdsO1aWIgc2VsbGUgdXVyaW1pc2VrcyBrYXN1dGFkYT8NCg0KLSAgIDIgTWlsbGluZSBvbiB0ZWh0dWQgc2FtbXVkZSBqYW90dXMgc3VndWRlIGthdXBhPyBWaWhqZWQ6DQoNCiAgICAtICAgZXQgam9vbmlzdGFkYSBoaXN0b2dyYW1taWQgw7xrc3RlaXNlIHBlYWxlIHRhc3ViIHBhbm5hIGBwb3NpdGlvbiA9ICJpZGVudGl0eSJgDQoNCiAgICAtICAgYXJndW1lbnQgYGFscGhhYCBrb250cm9sbGliIHbDpHJ2aWRlIGzDpGJpcGFpc3R2dXN0DQoNCi0gICAzIEt1bW1hIHNvbyBlc2luZGFqYWQgdGVldmFkIG1lZGlhYW5pcyB2w6RoZW0gc2FtbXVzaWQ/DQoNCi0gICA0IFRlZSBsw6RiaSBzZWUgc2FtYSB2w7VyZGx1cyB2YW51c2VncnVwcGlkZSBrYXVwYS4gS2FzIGrDpHJlbGR1cyBvbiBzYW1hPw0KDQotICAgNSBWYWF0YSB2YW51c2VncnVwcGlkZSBhcnZ1a3VzdCBzdWd1ZGUga2F1cGEuIEthcyBqYW90dXMgb24gc2FybmFuZSB2w7VpIGVyaW5ldj8NCg0KLSAgIDYgS2FzIHZhbnVzZSBqYSB0ZWh0dWQgc2FtbXVkZSB2YWhlbCBvbiBzZW9zPyBLYXMgc2VvcyB0dW5kdWIgbGluZWFhcm5lPw0KDQotICAgNyBNaWxsaW5lIG9uIHNlb3Mga2VoYW1hc3NpIGluZGVrc2kgamEgc2FtbXVkZSB2YWhlbD8gS2FzIHNlb3Mgb24gbGluZWFhcm5lIGphIHbDtWkgb24gdGVndSBtaWxsZWdpIGtlZXJ1a2FtYWdhPw0KDQpgYGB7cn0NCg0KIzENCmdncGxvdChibWksIGFlcyh4ID0gU3RlcHMpKSArDQogIGdlb21faGlzdG9ncmFtKCkNCg0KZ2dwbG90KGJtaSwgYWVzKHggPSBTdGVwcykpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDEwMCkNCg0KZ2dwbG90KGJtaSwgYWVzKHggPSBTdGVwcykpICsNCiAgZ2VvbV9kZW5zaXR5KCkNCg0KZ2dwbG90KGJtaSwgYWVzKHggPSBTdGVwcykpICsNCiAgZ2VvbV9ib3hwbG90KCkNCmBgYA0KDQpgYGB7cn0NCg0KIzINCmdncGxvdChibWksIGFlcyh4ID0gU3RlcHMsIGZpbGw9R2VuZGVyKSkgKw0KICAgIGdlb21faGlzdG9ncmFtKHBvc2l0aW9uID0gImlkZW50aXR5IiwgYWxwaGE9MC4zKQ0KDQpnZ3Bsb3QoYm1pLCBhZXMoeCA9IFN0ZXBzLCBmaWxsPUdlbmRlciwgY29sb3I9R2VuZGVyKSkgKw0KICAgIGdlb21faGlzdG9ncmFtKHBvc2l0aW9uID0gImlkZW50aXR5IiwgYWxwaGE9MC4zKQ0KDQoNCmdncGxvdChibWksIGFlcyh4ID0gU3RlcHMsIGZpbGw9R2VuZGVyLCBjb2xvcj1HZW5kZXIpKSArDQogIGdlb21fZGVuc2l0eShwb3NpdGlvbiA9ICJpZGVudGl0eSIsIGFscGhhPTAuMykNCg0KYGBgDQoNCmBgYHtyfQ0KDQojMw0KDQpnZ3Bsb3QoYm1pLCBhZXMoeCA9IFN0ZXBzLCB5PUdlbmRlcikpICsNCiAgZ2VvbV9ib3hwbG90KCkNCg0KYGBgDQoNCmBgYHtyfQ0KDQojNA0KZ2dwbG90KGJtaSwgYWVzKHggPSBTdGVwcywgeT1BZ2VHcm91cCwgZmlsbD1HZW5kZXIpKSArDQogIGdlb21fYm94cGxvdCgpDQpgYGANCg0KYGBge3J9DQoNCiM1DQpnZ3Bsb3QoYm1pLCBhZXMoeCA9IEdlbmRlciwgZmlsbD1BZ2VHcm91cCkpICsNCiAgZ2VvbV9iYXIoKQ0KDQpnZ3Bsb3QoYm1pLCBhZXMoeCA9IEdlbmRlciwgZmlsbD1BZ2VHcm91cCkpICsNCiAgZ2VvbV9iYXIocG9zaXRpb249ImRvZGdlIikNCg0KZ2dwbG90KGJtaSwgYWVzKHggPSBHZW5kZXIsIGZpbGw9QWdlR3JvdXApKSArDQogIGdlb21fYmFyKHBvc2l0aW9uPSJmaWxsIikNCmBgYA0KDQpgYGB7cn0NCg0KIzYNCmdncGxvdChibWksIGFlcyh4ID0gQWdlLCB5PVN0ZXBzKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3Ntb290aCgpDQoNCmdncGxvdChibWksIGFlcyh4ID0gQWdlLCB5PVN0ZXBzKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKQ0KYGBgDQoNCmBgYHtyfQ0KDQojNyANCmdncGxvdChibWksIGFlcyh4ID0gQk1JLCB5PVN0ZXBzKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3Ntb290aCgpDQoNCmdncGxvdChibWksIGFlcyh5ID0gQk1JLCB4PVN0ZXBzKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKQ0KYGBgDQoNCiMjIEtvZHVuZSDDvGxlc2FubmUNCg0KRmFpbGlzIGB5bGV2YWF0dXNlZC5SRGF0YWAgb24gYW5kbWVzdGlrIGvDtWlnaSBFZXN0aXMgdG9pbWUgcGFuZHVkIHPDtWlkdWtpdGUgdGVobmlsaXN0ZSDDvGxldmFhdHVzdGUga29odGEuIFR1bm51c3RlIGtvaHRhIGxpc2FpbmZvdCBwYWxqdSBwb2xlLCBrdWlkIG5pbWVkIHBlYWtzIHN1aHQgc2VsZ2VkIG9sZW1hLiBBbmRtZXN0aWsgcMOkcmluZWIgZWVzdGkgYXZhYW5kbWV0ZSBwb3J0YWFsaXN0OiA8aHR0cHM6Ly9hdmFhbmRtZWQuZWVzdGkuZWUvZGF0YXNldHMvbWFpc21hYXNvaWR1a2l0ZS10ZWhub3VsZXZhYXR1c2VkLWVlc3Rpcz4NCg0Kw5xsZXNhbmRla3Mgb24gc2VsbGUgYW5kbWVzdGlrdSBww7VoamFsIGpvb25pc3RhZGEgdsOkbGphIGdyYWFmaWsgbWlzIHRvb2IgdsOkbGphIG1pbmdpIGh1dml0YXZhIHNlb3NlLiBBbmRtZXN0aWsgb24gc3V1ciBqYSBncmFhZmlrIGVpIHBlYSBrYWphc3RhbWEgdGVydmV0IGFuZG1lc3Rpa2t1LCB2YWlkIHbDtWliIGtlc2tlbmR1ZGEgbWluZ2lsZSBhbmRtZXRlIGFsYW1odWxnYWxlLg0KDQpTZWxsZWwgZ3JhYWZpa3VsIHbDtWliIG9sbGEgbWl0dSBwYW5lZWxpLCBrdWlkIHBlYWIgb2xlbWEgc2lpc2tpICoqw7xrcyoqIGZhaWwsIG1pcyB2w6RsamEgdHLDvGtraWRlcyBtYWh1a3Mgw7xoZWxlIGxlaGVsZSBqYSBvbGVrcyBsb2V0YXYuIEt1bmEgYW5kbWVkIG9uIGtlZXJ1a2FkIHbDtWliIHBpbGRpIHNhbHZlc3RhZGEgc3V1cmVtYW5hLCBrdWkgUnN0dWRpbyBncmFhZmlrdSBha25hc3NlIG1haHViIChrYXN1dGFkZXMga8Okc2t1IGBnZ3NhdmVgIGphIGFyZ3VtZW50ZSBgaGVpZ2h0YCBqYSBgd2lkdGhgKSwgZXQga8O1aWdlbCB2YWphbGlrdWwgcGlpc2F2YWx0IHJ1dW1pIG9sZWtzLg0KDQpFc2l0YWRhIHR1bGViIGdyYWFmaWt1dCBnZW5lcmVlcml2ICoqa29vZCoqLCBww7VoamVuZHVzIG1pa3MganVzdCBhbnR1ZCB0w7zDvHBpIGdyYWFmaWsodWQpIG9uIG5lbmRlIGFuZG1ldGUgbsOkaXRhbWlzZWtzIGhlYSBqYSBrYSBtw7VuZSBsYXVzZWxpbmUgKipqw6RyZWxkdXMqKiwgbWlsbGUgdGUgcGlsZGlsdCBvbGV0ZSB2w6RsamEgbHVnZW51ZC4NCg0KR3JhYWZpayBwZWFiIHZhc3RhbWEgasOkcmduZXZhdGVsZSB0aW5naW11c3RlbGUuDQoNCi0gICBLYXN1dGF0dWQgb24gdsOkaGVtYWx0IDUgZXJpbmV2YXQgdHVubnVzdA0KDQotICAgS2FzdXRhdHVkIG9uIHbDpGhlbWFsdCAyIGVyaW5ldmF0IGdlb21cX1wqIGZ1bmt0c2lvb25pDQoNCi0gICBPbiBtb2RpZml0c2Vlcml0dWQgZ3JhYWZpa3UgZWxlbWVudGlkZSB2w6RsamFuw6RnZW1pc3QgbmluZyBuZWVkIG11dWRhdHVzZWQgb24gYXNqYWtvaGFzZWQNCg0KLSAgIE9uIHZhbGl0dWQgYW5kbWV0ZWxlIHNvYml2IHZpc3VhbGlzZWVyaW1pc2UgbWVldG9kDQoNCi0gICBHcmFhZmlrIGVpIHZhamEgbGlzYXNlbGdpdHVzaSBuaW5nIG9uIGtlcmdlc3RpIGxvZXRhdiAoa8O1aWsgdGVrc3RpZCBzdXVydGUgYWxndXN0w6RodGVkZWdhLCBncmFtbWF0aWxpc2VsdCBrb3JyZWt0c2VkLCBwaWlzYXZhbHQga2lyamVsZGF2YWQpLg0KDQotICAgVGVrc3RpbGlzZWQgasOkcmVsZHVzZWQgamEgZ3JhYWZpayBsw6RoZXZhZCBrb2trdS4NCg0KYGBge3J9DQoNCmxvYWQoInlsZXZhYXR1c2VkLlJEYXRhIiwgdmVyYm9zZSA9IFQpDQoNCnlsZXZhYXR1c2VkDQpgYGANCg0KYGBge3J9DQpuYW1lcyh5bGV2YWF0dXNlZCkgIyBjb2xuYW1lcyh5bGV2YWF0dXNlZCkNCg0KDQp1bmlxdWUoeWxldmFhdHVzZWQkWUxFVkFBVFVTT1RTVVMpDQoNCg0Kc3RyKHlsZXZhYXR1c2VkKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHBhdGNod29yaykNCmBgYA0KDQpgYGB7cn0NCnlsZXYgPC0geWxldmFhdHVzZWQgJT4lDQogIG11dGF0ZSgNCiAgICBSSUtLRUQgPSBpZmVsc2UoaXMubmEoUklLS0VEKSwgIiIsIFJJS0tFRCksDQogICAgVklHQURFX0FSViA9IGlmZWxzZShSSUtLRUQgPT0gIiIsIDAsIHN0cl9jb3VudChSSUtLRUQsICI7IikgKyAxKSwNCiAgKSAlPiUNCiAgZmlsdGVyKHN0cl9zdGFydHMoS0FURUdPT1JJQSwgIk0iKSAmICFpcy5uYShLQVRFR09PUklBKSkgJT4lDQogbXV0YXRlKEtFUkVUWVlQX0dSVVBQID0gY2FzZV93aGVuKA0KICAgIEtFUkVUWVlQICVpbiUgYygiTUFIVFVOSVZFUlNBQUwiLCAiVU5JVkVSU0FBTCIsICJMVVVLUMOEUkEiLCAiU0VEQUFOIiwNCiAgICAgICAgICAgICAgICAgICAgIktVUEVFIiwgIkxJTVVTSUlOIiwgIktPTUJJIikgfiAiU8O1aWR1YXV0byIsDQoNCiAgICBLRVJFVFlZUCAlaW4lIGMoIkxBSFRJTkUiLCAiUElLQVAiLCANCiAgICAgICAgICAgICAgICAgICAgIlNJSFRPVFNUQVJCRUxJTkUiLCAiRVJJT1RTVEFSQkVMSU5FIFPDlUlEVUsiKSB+ICJLYXViaWsgLyB0w7bDtmF1dG8iLA0KDQogICAgS0VSRVRZWVAgJWluJSBjKCJNSVRNRU9UU1RBUkJFTElORSBTw5VJRFVLIikgfiAiTWl0bWVvdHN0YXJiZWxpbmUiLA0KDQogICAgS0VSRVRZWVAgJWluJSBjKCJCVVNTIiwgIkxJSUdFTkRCVVNTIiwgIktPUlJVU0JVU1MiLCAiVFJPTEwiKSB+ICJCdXNzIiwNCg0KICAgIEtFUkVUWVlQICVpbiUgYygiS0lJUkFCSSIsICJNQVRVU0VBVVRPIiwgIkVMQU1VIikgfiAiRXJpc8O1aWR1ayIsDQoNCiAgICBUUlVFIH4gTkENCiAgKSkNCiAgI3NhbXBsZV9uKDIwMDAwKQ0KDQp5bGV2DQpgYGANCg0KYGBge3J9DQojdW5pcXVlKHlsZXYkWUxFVkFBVFVTT1RTVVMpDQoNCnVuaXF1ZSh5bGV2JEtFUkVUWVlQKQ0KYGBgDQoNCmBgYHtyfQ0KIyBWYW51cyB2cyBtaXR0ZV9wb3NpdGlpdm5lIMO8bGV2YWF0dXNvdHN1cyAoTTEgamEgbTFnIGthdGVnb29yaWEgKHPDtWlkdXVhdG9kIGphIGJ1c3NpZCkpDQoNCmxpYnJhcnkoc2NhbGVzKQ0KcGFsZXR0ID0gaHVlX3BhbCgpKDgpDQoNCmthdGVnb29yaWFfdsOkcnZpZCA9IGMoDQogICJNMSIgICAgID0gcGFsZXR0WzJdLA0KICAiTTFHIiAgICA9IHBhbGV0dFs0XSwNCiAgIk0yIiAgICAgPSBwYWxldHRbNl0sDQogICJNMyIgICAgID0gcGFsZXR0WzhdDQopDQoNCg0KbTFfbTFnIDwtIHlsZXYgJT4lDQogIGZpbHRlcighaXMubmEoRVNNQU5FX1JFR19BQVNUQSksICFpcy5uYShZTEVWQUFUVVNPVFNVUykpICU+JQ0KICBmaWx0ZXIoWUxFVkFBVFVTT1RTVVMgJWluJSBjKCJFSV9WQVNUQV9OT1VFVEVMRSIsICJTT0lUTUlTRUtTX0tPTEJNQVRVIikpICU+JQ0KICBmaWx0ZXIoS0FURUdPT1JJQSAlaW4lIGMoIk0xIiwgIk0xRyIpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gRVNNQU5FX1JFR19BQVNUQSwgY29sb3IgPSBLQVRFR09PUklBLCBmaWxsID0gS0FURUdPT1JJQSkpICsNCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC4yKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiU8O1aWR1YXV0b2QiLA0KICAgIHggPSAiRXNtYW5lIHJlZ2lzdHJlZXJpbXNlIGFhc3RhIiwNCiAgICB5ID0gIlRpaGVkdXMiLA0KICAgIGZpbGwgPSAiS2F0ZWdvb3JpYSIsDQogICAgY29sb3IgPSAiS2F0ZWdvb3JpYSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gInBsYWluIiwgc2l6ZSA9IDEyKSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0ga2F0ZWdvb3JpYV92w6RydmlkKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGthdGVnb29yaWFfdsOkcnZpZCkgDQoNCm0yX20zIDwtIHlsZXYgJT4lDQogIGZpbHRlcighaXMubmEoRVNNQU5FX1JFR19BQVNUQSksICFpcy5uYShZTEVWQUFUVVNPVFNVUykpICU+JQ0KICBmaWx0ZXIoWUxFVkFBVFVTT1RTVVMgJWluJSBjKCJFSV9WQVNUQV9OT1VFVEVMRSIsICJTT0lUTUlTRUtTX0tPTEJNQVRVIikpICU+JQ0KICBmaWx0ZXIoS0FURUdPT1JJQSAlaW4lIGMoIk0yIiwgIk0zIikpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBFU01BTkVfUkVHX0FBU1RBLCBjb2xvciA9IEtBVEVHT09SSUEsIGZpbGwgPSBLQVRFR09PUklBKSkgKw0KICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJCdXNzaWQiLA0KICAgIHggPSAiRXNtYW5lIHJlZ2lzdHJlZXJpbXNlIGFhc3RhIiwNCiAgICB5ID0gIlRpaGVkdXMiLA0KICAgIGZpbGwgPSAiS2F0ZWdvb3JpYSIsDQogICAgY29sb3IgPSAiS2F0ZWdvb3JpYSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gInBsYWluIiwgc2l6ZSA9IDEyKSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0ga2F0ZWdvb3JpYV92w6RydmlkKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGthdGVnb29yaWFfdsOkcnZpZCkgDQoNCg0KZ3JhYWZpazEgPC0gbTFfbTFnIC8gbTJfbTMgKw0KICAgcGxvdF9sYXlvdXQoZ3VpZGVzID0gImNvbGxlY3QiKSArDQogICBwbG90X2Fubm90YXRpb24oDQogICAgdGl0bGUgPSAiTmVnYXRpaXZuZSDDvGxldmFhdHVzb3RzdXMiLA0KICAgIHN1YnRpdGxlID0gIk0ta2F0ZWdvb3JpYSBzw7VpZHVraWQiLA0KICAgICNjYXB0aW9uID0gIkFsbGlrYXM6ID8/IHRydXN0IG1lIGJybyIsDQogICAgdGhlbWUgPSB0aGVtZSgNCiAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE2KSwNCiAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKQ0KICAgICkNCiAgKSANCg0KI2dyYWFmaWsxDQpgYGANCg0KYGBge3J9DQoNCg0KIyBBdXRvIGthdGVnb29yaWEgamEgdmlnYWRlIGFydg0KZ3JhYWZpazIgPC0geWxldiAlPiUNCiAgZmlsdGVyKCFpcy5uYShLQVRFR09PUklBKSwgIWlzLm5hKEtFUkVUWVlQX0dSVVBQKSkgJT4lDQogIGdyb3VwX2J5KEtBVEVHT09SSUEpICU+JQ0KICBnZ3Bsb3QoYWVzKHkgPSBLQVRFR09PUklBLCB4ID0gVklHQURFX0FSViwgY29sb3I9S0VSRVRZWVBfR1JVUFApKSArDQogIGdlb21fcG9pbnQocG9zaXRpb24gPSAiaml0dGVyIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlZpZ2FkZSBhcnYga2VyZXTDvMO8Ymkga29odGEiLA0KICAgIHN1YnRpdGxlID0gIk0ta2F0ZWdvb3JpYSBzw7VpZHVraWQiLA0KICAgIHkgPSAiS2VyZXTDvMO8cCIsDQogICAgeCA9ICJWaWdhZGUgQXJ2IiwNCiAgICBjb2xvciA9ICJLZXJldMO8w7xwIg0KICApICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMikgKyANCiAgIHRoZW1lKA0KICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTYpLA0KICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpDQogICAgKQ0KDQojZ3JhYWZpazINCmBgYA0KDQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTE2fQ0KDQpncmFhZmlrMSAvIGdyYWFmaWsyICsNCiAgIHBsb3RfbGF5b3V0KGd1aWRlcyA9ICJrZWVwIikNCmBgYA0KDQoqKk1hIHRhaHRzaW4gdXVyaWRhIGrDpHJnbmV2YXQ6KioNCg0KMSkgTWlkYSB2YW5lbSBhdXRvIHNlZGEgc3V1cmVtYSB0w7VlbsOkb3N1c2VnYSBrdWt1YiDDvGxldmFhdHVzZWwgYXV0byBsw6RiaS4NCg0KMikgU8O1aWR1YXV0b2RlbCBvbiB0YXZhbGlzZWx0IHJvaGtlbSB2aWd1IGt1aSBidXNzaWRlbCwga3VuYSBhdXRvc2lkIG9uIHJvaGtlbSB0ZWVkZWwga3VpIGJ1c3NlLg0KDQoqKkrDpHJlbGR1c2VkOioqDQoNCjEpIHPDtWlkdWF1dG9kOiBNaWRhIHZhbmVtIGF1dG8sIHNlZGEgc3V1cmVtIG9uIHTDtWVuw6Rvc3VzIMO8bGV2YWF0dXNlbCBsw6RiaSBrdWtrdWRhLiBcDQpCdXNzaWQ6IFZhbnVzIGVpIHNlbGdpdGEgb3RzZXNsZXQgbMOkYmlrdWtrdW1pc3QuIEJ1c3NpZGUgcHVodWwgbcO1anV0YWIgdHVsZW11c3QgcGlnZW0gYXN1dHVzaW50ZW5zaWl2c3VzIChzdXVyZW0gYWFzdGFuZSBsw6RiaXPDtWl0KSwgbWlzdMO1dHR1IHbDtWl2YWQga2EgdXVlbWFkIGJ1c3NpZCBzYWdlZGFtaW5pIGzDpGJpIGt1a2t1ZGEuDQoNCjIpIFPDtWlkdWF1dG9kZWwgb24gcm9oa2VtIMOkw6RybXVzbGlra2UgdmlnYWRlIHbDpMOkcnR1c2ksIGt1bmEgc8O1aWR1YXV0b3NpZCBvbiB2YWxpbWlzIHR1bmR1dmFsdCByb2hrZW0ga3VpIGJ1c3NlLiBWYWxpbWkgc3V1cnVzIHRla2l0YWIgbG9vbXVsaWt1bHQgc3V1cmVtYSBoYWp1dnVzZS4NCg==